#include "test.h"
#include "dag.h"

#include <set>
#include <vector>
#include <algorithm>

using namespace dag;
using namespace std;

bool equal_frames(const Frame& f1, const Frame& f2) {
	if (f1.bSize != f2.bSize ||
		f1.iSize != f2.iSize || 
		f1.fSize != f2.fSize ||
		f1.dSize != f1.dSize) {
		return false;
	}
	
	for (size_t i = 0; i < f1.bSize; i++) {
		if (f1.bools[i] != f2.bools[i]) {
			return false;
		}
	}
	
	for (size_t i = 0; i < f1.iSize; i++) {
		if (f1.ints[i] != f2.ints[i]) {
			return false;
		}
	}
	
	for (size_t i = 0; i < f1.fSize; i++) {
		if (f1.floats[i] != f2.floats[i]) {
			return false;
		}
	}
	
	for (size_t i = 0; i < f1.dSize; i++) {
		if (f1.doubles[i] != f2.doubles[i]) {
			return false;
		}
	}
	
	return true;
}

void seed_random(Frame& frame) {
	for (size_t i = 0; i < frame.bSize; i++) {
		frame.bools[i] = (rand() > RAND_MAX / 2);
	}
	
	for (size_t i = 0; i < frame.iSize; i++) {
		frame.ints[i] = rand();
	}
	
	for (size_t i = 0; i < frame.fSize; i++) {
		frame.floats[i] = rand();
	}
	
	for (size_t i = 0; i < frame.dSize; i++) {
		frame.doubles[i] = rand();
	}
}

bool equal_set(const set<size_t>& s1, const set<size_t>& s2) {
	vector<size_t> diff(max(s1.size(), s2.size()));
	
	vector<size_t>::iterator res = set_difference(s1.begin(), s1.end(), 
												  s2.begin(), s2.end(), 
												  diff.begin());
	return (res == diff.begin());
}

bool equal_link(const Link& l1, const Link& l2) {
	
	if (l1.size() != l2.size()) {
		return false;
	}
	
	const set<size_t>& l1fSet = l1.forwardSet();
	const set<size_t>& l1rSet = l1.reverseSet();
	const set<size_t>& l2fSet = l2.forwardSet();
	const set<size_t>& l2rSet = l2.reverseSet();
	
	if (!equal_set(l1fSet, l2fSet)) {
		return false;
	}
	
	if (!equal_set(l1rSet, l2rSet)) {
		return false;
	}
	
	set<size_t>::const_iterator iter;
	for (iter = l1fSet.begin(); iter != l1fSet.end(); iter++) {
		if (l1.forward(*iter) != l2.forward(*iter)) {
			return false;
		}
	}
	
	for (iter = l1rSet.begin(); iter != l1rSet.end(); iter++) {
		if (l1.reverse(*iter) != l2.reverse(*iter)) {
			return false;
		}
	}
	
	return true;
}

bool equal_frame_link(const FrameLink& fl1, const FrameLink& fl2) {
	return (equal_link(fl1.bLink, fl2.bLink) &&
			equal_link(fl1.iLink, fl2.iLink) &&
			equal_link(fl1.fLink, fl2.fLink) &&
			equal_link(fl1.dLink, fl2.dLink));
}

bool equal_frame_depot(const FrameDepot& d1, const FrameDepot& d2) {
	if (d1.spec() != d2.spec()) {
		return false;
	}
	
	if (d1.size() != d2.size()) {
		return false;
	}
	
	FrameSpec spec = d1.spec();
	for (size_t i = 0; i < d1.size(); i++) {
		for (size_t j = 0; j < spec.bSize; j++) {
			if (d1.bools(i)[j] != d2.bools(i)[j]) {
				return false;
			}
		}
		for (size_t j = 0; j < spec.iSize; j++) {
			if (d1.ints(i)[j] != d2.ints(i)[j]) {
				return false;
			}
		}
		for (size_t j = 0; j < spec.fSize; j++) {
			if (d1.floats(i)[j] != d2.floats(i)[j]) {
				return false;
			}
		}
		for (size_t j = 0; j < spec.dSize; j++) {
			if (d1.doubles(i)[j] != d2.doubles(i)[j]) {
				return false;
			}
		}
	}
	
	return true;
}
